home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #define NOKNET
- #define import_spp
- #define import_finfo
- #define import_knames
- #include <iraf.h>
-
- /*
- * WTAR -- Write a UNIX tar format file (on disk, tape, or to stdout)
- *
- * Switches:
- * f write to named file, otherwise write to stdout
- * t print name of each file written
- * v verbose; print full description of each file
- * d print debug messages
- * o omit binary files (e.g. when foreign host has
- * incompatible binary file format)
- */
-
- #define TBLOCK 512
- #define NBLOCK 20
- #define NAMSIZ 100
- #define MAXERR 20
- #define MAXTRYS 100
- #define SZ_TAPEBUFFER (TBLOCK * NBLOCK)
- #define RWXR_XR_X 0755
-
- /* File header structure. One of these precedes each file on the tape.
- * Each file occupies an integral number of TBLOCK size logical blocks
- * on the tape. The number of logical blocks per physical block is variable,
- * with at most NBLOCK logical blocks per physical tape block. Two zero
- * blocks mark the end of the tar file.
- */
- union hblock {
- char dummy[TBLOCK];
- struct header {
- char name[NAMSIZ]; /* NULL delimited */
- char mode[8]; /* octal, ascii */
- char uid[8];
- char gid[8];
- char size[12];
- char mtime[12];
- char chksum[8];
- char linkflag;
- char linkname[NAMSIZ];
- } dbuf;
- };
-
- /* Decoded file header.
- */
- struct fheader {
- char name[NAMSIZ];
- int mode;
- int uid;
- int gid;
- int isdir;
- long size;
- long mtime;
- long chksum;
- int linkflag;
- char linkname[NAMSIZ];
- };
-
- /* Map TAR file mode bits into characters for printed output.
- */
- struct _modebits {
- int code;
- char ch;
- } modebits[] = {
- 040000, 'd',
- 0400, 'r',
- 0200, 'w',
- 0100, 'x',
- 040, 'r',
- 020, 'w',
- 010, 'x',
- 04, 'r',
- 02, 'w',
- 01, 'x',
- 0, 0
- };
-
- int debug=NO; /* Print debugging messages */
- int omitbinary; /* omit binary files */
- int printfnames; /* Print file names */
- int verbose; /* Print everything */
-
- struct fheader *curfil;
- int nerrs;
- char *first_file;
- char tapeblock[SZ_TAPEBUFFER];
- char *nextblock = NULL;
- int nblocks;
- int in;
- int out = EOF;
-
- extern char *vfn2osfn();
- long os_utime();
-
-
- /* MAIN -- "wtar [-tvdo] [-f tarfile] [files]". If no files are listed the
- * current directory tree is used as input. If no output file is specified
- * output is to the standard output.
- */
- main (argc, argv)
- int argc;
- char *argv[];
- {
- static char *def_flist[2] = { ".", NULL };
- char *argp, **flist;
- int argno, ftype, i;
-
- ZZSTRT();
-
- flist = def_flist;
- omitbinary = NO;
- printfnames = debug;
- verbose = debug;
-
- if (debug) {
- printf ("wtar called with %d arguments:", argc);
- for (argno=1; (argp = argv[argno]) != NULL; argno++)
- printf (" %s", argp);
- printf ("\n");
- }
-
- /* Process the argument list.
- */
- for (argno=1; (argp = argv[argno]) != NULL; argno++) {
- if (*argp != '-') {
- flist = &argv[argno];
- break;
-
- } else {
- for (argp++; *argp; argp++) {
- switch (*argp) {
- case 'd':
- debug++;
- printfnames++;
- verbose++;
- break;
- case 't':
- printfnames++;
- break;
- case 'v':
- verbose++;
- break;
- case 'o':
- omitbinary++;
- break;
-
- case 'f':
- if (argv[argno+1]) {
- argno++;
- if (debug)
- printf ("open output file `%s'\n", argv[argno]);
- out = tape_open (argv[argno], 1);
- if (out == ERR) {
- fprintf (stderr,
- "cannot open `%s'\n", argv[argno]);
- ZZSTOP();
- exit (OSOK+1);
- }
- }
- break;
-
- default:
- fprintf (stderr,
- "Warning: unknown switch -%c\n", *argp);
- fflush (stderr);
- }
- }
- }
- }
-
- /* Write to the standard output if no output file specified.
- * The filename "stdin" is reserved.
- */
- if (out == ERR) {
- if (debug)
- printf ("output defaults to stdout\n");
- out = tape_open ("stdout", 1);
- }
-
- nextblock = tapeblock;
- nblocks = 0;
-
- /* Put each directory and file listed on the command line to
- * the tarfile.
- */
- for (i=0; (argp = flist[i]) != NULL; i++)
- if ((ftype = os_filetype (argp)) == DIRECTORY_FILE)
- putfiles (argp, out, "");
- else
- tarfileout (argp, out, ftype, "");
-
- /* Close the tarfile.
- */
- endtar (out);
- tape_close (out);
-
- ZZSTOP();
- exit (OSOK);
- }
-
-
- /* PUTFILES -- Put the named directory tree to the output tarfile. We chdir
- * to each subdirectory to minimize path searches and speed up execution.
- */
- putfiles (dir, out, path)
- char *dir; /* directory name */
- int out; /* output file */
- char *path; /* pathname of curr. directory */
- {
- char newpath[SZ_PATHNAME+1];
- char fname[SZ_PATHNAME+1];
- int ftype, dp;
-
- if (debug)
- printf ("putfiles (%s, %d, %s)\n", dir, out, path);
-
- /* Put the directory file itself to the output as a file.
- */
- tarfileout (dir, out, DIRECTORY_FILE, path);
-
- if ((dp = os_diropen (dir)) == ERR) {
- fprintf (stderr, "cannot open subdirectory `%s%s'\n", path, dir);
- fflush (stderr);
- return;
- }
-
- sprintf (newpath, "%s%s/", path, dir);
- if (debug)
- printf ("change directory to %s\n", newpath);
- if (os_chdir (dir) == ERR) {
- os_dirclose (dp);
- fprintf (stderr, "cannot change directory to `%s'\n", newpath);
- fflush (stderr);
- return;
- }
-
- /* Put each file in the directory to the output file. Recursively
- * read any directories encountered.
- */
- while (os_gfdir (dp, fname, SZ_PATHNAME) > 0)
- if ((ftype = os_filetype (fname)) == DIRECTORY_FILE)
- putfiles (fname, out, newpath);
- else
- tarfileout (fname, out, ftype, newpath);
-
- if (debug)
- printf ("return from subdirectory %s\n", newpath);
- if (os_chdir ("..") == ERR) {
- fprintf (stderr, "cannot return from subdirectory `%s'\n", newpath);
- fflush (stderr);
- }
-
- os_dirclose (dp);
- }
-
-
- /* TARFILEOUT -- Write the named file to the output in tar format.
- */
- tarfileout (fname, out, ftype, path)
- char *fname; /* file to be output */
- int out; /* output stream */
- int ftype; /* file type */
- char *path; /* current path */
- {
- struct _finfo fi;
- struct fheader fh;
- int status;
-
- if (debug)
- printf ("put file `%s', type %d\n", fname, ftype);
-
- if (ftype == BINARY_FILE && omitbinary) {
- if (printfnames) {
- fprintf (stderr, "omit binary file `%s'\n", fname);
- fflush (stderr);
- }
- return;
- }
-
- /* Get info on file to make file header.
- */
- ZFINFO ((PKCHAR *)vfn2osfn(fname,0), &fi, &status);
- if (status == XERR) {
- fprintf (stderr, "Warning: can't get info on file `%s'\n", fname);
- fflush (stderr);
- return;
- }
-
- /* Format and output the file header.
- */
- strcpy (fh.name, path);
- strcat (fh.name, fname);
-
- if (ftype == DIRECTORY_FILE) {
- strcat (fh.name, "/");
- fh.size = 0;
- fh.isdir = 1;
- } else {
- fh.size = fi.fi_size;
- fh.isdir = 0;
- }
-
- os_getowner (fname, &fh.uid, &fh.gid);
- fh.linkflag = 0; /* no links allowed */
- strcpy (fh.linkname, "");
- fh.mode = u_fmode (fi.fi_perm, fi.fi_type);
- fh.mtime = os_utime (fi.fi_mtime);
-
- if (putheader (&fh, out) == EOF) {
- fprintf (stderr,
- "Warning: could not write file header for `%s'\n", fname);
- fflush (stderr);
- return;
- }
-
- /* Copy the file data.
- */
- if (fh.size > 0 && !fh.isdir)
- copyfile (fname, &fh, ftype, out);
-
- if (printfnames) {
- printheader (stdout, &fh, verbose);
- fflush (stdout);
- }
- }
-
-
- /* PUTHEADER -- Encode and write the file header to the output tarfile.
- */
- putheader (fh, out)
- register struct fheader *fh; /* (input) file header */
- int out; /* output file descriptor */
- {
- register char *ip, *op;
- register int n;
- union hblock hb;
-
- /* Clear the header block. */
- for (n=0; n < TBLOCK; n++)
- hb.dummy[n] = '\0';
-
- /* Encode the file header.
- */
- strcpy (hb.dbuf.name, fh->name);
- sprintf (hb.dbuf.mode, "%6o ", fh->mode);
- sprintf (hb.dbuf.uid, "%6o ", fh->uid);
- sprintf (hb.dbuf.gid, "%6o ", fh->gid);
- sprintf (hb.dbuf.size, "%11lo ", fh->size);
- sprintf (hb.dbuf.mtime, "%11lo ", fh->mtime);
-
- n = fh->linkflag;
- if (n >= '0' && n <= '9')
- hb.dbuf.linkflag = n - '0';
- else
- hb.dbuf.linkflag = 0;
- strcpy (hb.dbuf.linkname, fh->linkname);
-
- /* Encode the checksum value for the file header and then
- * write the field. Calculate the checksum with the checksum
- * field blanked out. Compute the actual checksum as the sum of
- * all bytes in the header block. A sum of zero indicates the
- * end of the tar file.
- */
- for (n=0; n < 8; n++)
- hb.dbuf.chksum[n] = ' ';
-
- sprintf (hb.dbuf.chksum, "%6.8o", cchksum (hb.dummy, TBLOCK));
-
- if (debug) {
- printf ("File header:\n");
- printf (" name = %s\n", hb.dbuf.name);
- printf (" mode = %s\n", hb.dbuf.mode);
- printf (" uid = %s\n", hb.dbuf.uid);
- printf (" gid = %s\n", hb.dbuf.gid);
- printf (" size = %-12.12s\n", hb.dbuf.size);
- printf (" mtime = %-12.12s\n", hb.dbuf.mtime);
- printf (" chksum = %s\n", hb.dbuf.chksum);
- printf (" linkflag = %c\n", hb.dbuf.linkflag);
- printf (" linkname = %s\n", hb.dbuf.linkname);
- fflush (stdout);
- }
-
- /* Write the header to the tarfile.
- */
- return (putblock (out, hb.dummy));
- }
-
-
- /* CCHKSUM -- Compute the checksum of a byte array.
- */
- cchksum (p, nbytes)
- register char *p;
- register int nbytes;
- {
- register int sum;
-
- for (sum=0; --nbytes >= 0; )
- sum += *p++;
-
- return (sum);
- }
-
-
- /* PRINTHEADER -- Print the file header in either short or long (verbose)
- * format, e.g.:
- * drwxr-xr-x 9 tody 1024 Nov 3 17:53 .
- */
- printheader (fp, fh, verbose)
- FILE *fp; /* output file */
- register struct fheader *fh; /* file header struct */
- int verbose; /* long format output */
- {
- register struct _modebits *mp;
- char *tp, *ctime();
-
- if (!verbose) {
- fprintf (fp, "%s\n", fh->name);
- return;
- }
-
- for (mp=modebits; mp->code; mp++)
- fprintf (fp, "%c", mp->code & fh->mode ? mp->ch : '-');
-
- tp = ctime (&fh->mtime);
- fprintf (fp, "%3d %4d %2d %8d %-12.12s %-4.4s %s",
- fh->linkflag,
- fh->uid,
- fh->gid,
- fh->size,
- tp + 4, tp + 20,
- fh->name);
-
- if (fh->linkflag)
- fprintf (fp, " -> %s\n", fh->linkname);
- else
- fprintf (fp, "\n");
- }
-
-
- /* COPYFILE -- Copy bytes from the input file to the output file. Each file
- * consists of a integral number of TBLOCK size blocks on the output file.
- */
- copyfile (fname, fh, ftype, out)
- char *fname; /* file being read from */
- struct fheader *fh; /* file header structure */
- int ftype; /* file type, text or binary */
- int out; /* output file */
- {
- register char *bp;
- register int i;
- int nbytes, nleft, blocks, fd, count, total, ch;
- char buf[TBLOCK*2];
-
- bp = buf;
- total = nbytes = 0;
- blocks = (fh->size + TBLOCK - 1 ) / TBLOCK;
-
- if ((fd = os_open (fname, 0, ftype)) == ERR) {
- fprintf (stderr, "Warning: cannot open file `%s'\n", fname);
- fflush (stderr);
- goto pad_;
- }
-
- while (blocks > 0) {
- if ((count = os_read (fd, bp, TBLOCK)) == ERR || count > TBLOCK) {
- fprintf (stderr, "Warning: file read error on `%s'\n", fname);
- fflush (stderr);
- if (nerrs++ > MAXERR) {
- fprintf (stderr, "Too many errors\n");
- exit (OSOK+1);
- }
- } else {
- /* Buffer input to TBLOCK blocks.
- */
- if (count == 0) /* EOF */
- break;
- else if ((nbytes += count) < TBLOCK)
- bp += count;
- else {
- putblock (out, buf);
- blocks--;
-
- /* Copy overflow back to beginning... */
- if (nbytes > TBLOCK) {
- nleft = nbytes - TBLOCK;
- os_amovb (&buf[TBLOCK], buf, nbytes - TBLOCK);
- } else
- nleft = 0;
-
- bp = (char *) ((int)buf + nleft);
- total += nbytes;
- nbytes = nleft;
- }
- }
- }
-
- os_close (fd);
-
- /* Fill current block and subsequent full blocks until the number of
- * bytes specified in the file header have been output. All files
- * occupy an integral number of 512 byte blocks on tape. For text
- * files, pad with spaces, otherwise pad with nulls. Also, for text
- * files, add newlines to avoid excessively long lines.
- */
- pad_:
- ch = (ftype == TEXT_FILE) ? ' ' : '\0';
- while (blocks > 0) {
- for (i=nbytes; i < TBLOCK; i++)
- if (ftype == TEXT_FILE && i % 64 == 0)
- buf[i] = '\n';
- else
- buf[i] = ch;
-
- if (ftype == TEXT_FILE)
- buf[TBLOCK-1] = '\n';
-
- putblock (out, buf);
- blocks--;
- nbytes = 0;
- }
- }
-
-
- /* PUTBLOCK -- Write a block to tape (buffered).
- */
- putblock (out, buf)
- int out;
- char *buf;
- {
- int nbytes = 0;
-
- if (buf) {
- os_amovb (buf, nextblock, TBLOCK);
- nextblock += TBLOCK;
- if (++nblocks == NBLOCK)
- nbytes = SZ_TAPEBUFFER;
- } else
- nbytes = nblocks * TBLOCK;
-
- if (nbytes > 0) {
- if (tape_write (out, tapeblock, nbytes) < nbytes) {
- fprintf (stderr, "Warning: write error on tarfile\n");
- fflush (stderr);
- }
-
- nextblock = tapeblock;
- nblocks = 0;
- }
-
- return (TBLOCK);
- }
-
-
- /* ENDTAR -- Write the end of the tar file, i.e., two zero blocks.
- */
- endtar (out)
- int out;
- {
- register int i;
- union hblock hb;
-
- if (debug)
- printf ("write end of tar file\n");
-
- for (i=0; i < TBLOCK; i++)
- hb.dummy[i] = '\0';
-
- putblock (out, hb.dummy); /* write 2 null blocks */
- putblock (out, hb.dummy);
- putblock (out, 0); /* flush tape buffer */
- }
-
-
- /* U_FMODE -- Convert the IRAF file mode bits to the corresponding UNIX bits
- * for the tar file header.
- */
- u_fmode (iraf_fmode, ftype)
- int iraf_fmode;
- int ftype;
- {
- register int in = iraf_fmode;
- register int m = 0;
- int exec;
-
- exec = (ftype == FI_DIRECTORY || ftype == FI_EXECUTABLE);
-
- if (in & 001) m |= 0400; /* Owner READ */
- if (in & 002) m |= 0200; /* WRITE */
- if (exec) m |= 0100; /* EXECUTE */
-
- if (in & 004) m |= 040; /* Group READ */
- if (in & 010) m |= 020; /* WRITE */
- if (exec) m |= 010; /* EXECUTE */
-
- if (in & 020) m |= 004; /* World READ */
- if (in & 040) m |= 002; /* WRITE */
- if (exec) m |= 001; /* EXECUTE */
-
- return (m);
- }
-